<!--
 * @description 组件
 * @author: 陈陈
 * @date: 2025/05/09
 * @phone: 18560000860
 * @email: 18560000860@qq.com
 * @company: 济南晨霜信息技术有限公司 /
 * @business: 承接前后端项目的开发
-->
<template>
	<view
		class="pure-calendar"
		:class="_classes"
		:style="_styles"
	>
		<view
			class="pure-calendar__header"
			v-if="showHeader"
		>
			<view class="pure-calendar__title">{{ title }}</view>
		</view>
		<view class="pure-calendar__topic">
			<view class="pure-calendar__topic__left">
				<view
					class="pure-calendar__change-button pure-calendar__change-button--prev-year"
					:class="{ 'pure-calendar__change-button--disabled': _disabledPrevYear }"
					:hover-class="hoverClass"
					@tap="_onPrevYear"
					v-if="switchMode === 'year-month'"
				>
					<pure-icon :name="prevYearIconName"></pure-icon>
				</view>
				<view
					class="pure-calendar__change-button pure-calendar__change-button--prev-month"
					:class="{ 'pure-calendar__change-button--disabled': _disabledPrevMonth }"
					:hover-class="hoverClass"
					@tap="_onPrevMonth"
					v-if="switchMode !== 'none'"
				>
					<pure-icon :name="prevMonthIconName"></pure-icon>
				</view>
			</view>
			<view class="pure-calendar__topic__text">{{ _topicText }}</view>
			<view class="pure-calendar__topic__right">
				<view
					class="pure-calendar__change-button pure-calendar__change-button--next-month"
					:class="{ 'pure-calendar__change-button--disabled': _disabledNextMonth }"
					:hover-class="hoverClass"
					@tap="_onNextMonth"
					v-if="switchMode !== 'none'"
				>
					<pure-icon :name="nextMonthIconName"></pure-icon>
				</view>
				<view
					class="pure-calendar__change-button pure-calendar__change-button--next-year"
					:class="{ 'pure-calendar__change-button--disabled': _disabledNextYear }"
					:hover-class="hoverClass"
					@tap="_onNextYear"
					v-if="switchMode === 'year-month'"
				>
					<pure-icon :name="nextYearIconName"></pure-icon>
				</view>
			</view>
		</view>
		<view class="pure-calendar__week">
			<view
				class="pure-calendar__week__item"
				v-for="item in _weeks"
				:key="item"
				>{{ item }}</view
			>
		</view>
		<view class="pure-calendar__body">
			<swiper
				class="pure-calendar__list"
				:current="_current"
				@change="_onChange"
			>
				<swiper-item
					class="pure-calendar__month"
					v-for="item in _months"
					:key="item.year + item.month"
				>
					<view class="pure-calendar__month__days">
						<view
							class="pure-calendar__month__day pure-calendar__month__day--prev"
							:class="_calcDayClasses(day)"
							v-for="day in item.prevDays"
							:key="`prev-${day.year}-${day.month}-${day.day}`"
						>
							<view class="pure-calendar__month__day__content">
								<slot :data="day">
									<text class="pure-calendar__month__day__text">{{ _calcDayText(day) }}</text>
								</slot>
							</view>
						</view>
						<view
							class="pure-calendar__month__day"
							:class="_calcDayClasses(day)"
							v-for="day in item.days"
							:key="`day-${day.year}-${day.month}-${day.day}`"
							:hover-class="hoverClass"
							@tap="_onClick(day)"
						>
							<view class="pure-calendar__month__day__content">
								<slot :data="day">
									<text class="pure-calendar__month__day__text">{{ _calcDayText(day) }}</text>
								</slot>
							</view>
						</view>
						<view
							class="pure-calendar__month__day pure-calendar__month__day--next"
							:class="_calcDayClasses(day)"
							v-for="day in item.nextDays"
							:key="`next-${day.year}-${day.month}-${day.day}`"
						>
							<view class="pure-calendar__month__day__content">
								<slot :data="day">
									<text class="pure-calendar__month__day__text">{{ _calcDayText(day) }}</text>
								</slot>
							</view>
						</view>
						<view
							class="pure-calendar__month__text"
							v-if="showMark"
						>
							<slot
								name="mark"
								:data="item"
							>
								{{ _calcMonthText(item) }}
							</slot>
						</view>
					</view>
				</swiper-item>
			</swiper>
		</view>
	</view>
</template>

<script>
	import commonComponentOptions from "../../config/options";
	export default {
		options: commonComponentOptions
	};
</script>

<script setup>
	import { ref, computed, watch, onMounted } from "vue";
	import props from "./props";
	import { dateParse, generateUUID, isFunction } from "@/uni_modules/pure-utils";

	// -------------------------------------------------------------------------------- Refs
	// 激活项下标
	const _current = ref(-1);

	// 展示年
	const _currentYear = computed(() => {
		return _months.value[_current.value]?.year;
	});

	// 展示月
	const _currentMonth = computed(() => {
		return _months.value[_current.value]?.month;
	});

	// 选中的日期
	const _selectedDates = ref([]);

	// -------------------------------------------------------------------------------- Props
	const _props = defineProps(props);

	// -------------------------------------------------------------------------------- Emits
	const _emits = defineEmits(["onSelect"]);

	// -------------------------------------------------------------------------------- Classes
	const _classes = computed(() => {
		const array = [];
		// 是否只读
		if (_props.readonly) array.push("pure-calendar--readonly");

		return array;
	});

	// -------------------------------------------------------------------------------- Styles
	const _styles = computed(() => {
		const array = [];

		// 选中时的背景
		if (_props.selectBackground) array.push(`--pure-calendar-day-selected-background: ${_props.selectBackground}`);

		// 选中时的文本颜色
		if (_props.selectTextColor) array.push(`--pure-calendar-day-selected-text-color: ${_props.selectTextColor}`);

		return array;
	});

	// 周
	const _weeks = computed(() => {
		if (_props?.weekStart === 0) {
			return ["日", "一", "二", "三", "四", "五", "六"];
		}
		return ["一", "二", "三", "四", "五", "六", "日"];
	});

	// 顶部文本
	const _topicText = computed(() => {
		const year = _months.value[_current.value]?.year;
		const month = _months.value[_current.value]?.month;
		if (year === undefined || month === undefined) return "";
		return `${year}年${month + 1}月`;
	});

	// 组织月份列表数据
	const _months = computed(() => {
		// 开始日期
		let startDate = dateParse(_props.startDate);

		// 结束日期
		let endDate = dateParse(_props.endDate);

		// 月份列表
		const months = [];

		// 生成数据
		while (startDate <= endDate) {
			const year = startDate.getFullYear();
			const month = startDate.getMonth();

			// 得到这个月的所有日期
			const days = [];
			for (let i = 1; i <= new Date(year, month + 1, 0).getDate(); i++) {
				const day = {
					year,
					month,
					day: i,
					date: new Date(year, month, i)
				};
				days.push(day);
			}

			// 这个月的第一天是周几
			const firstDay = new Date(year, month, 1).getDay();

			// 月前面需要添加的天数
			const prevDays = [];
			const prevAddDays = _props?.weekStart === 0 ? firstDay : firstDay - 1;
			// 如果需要添加的天数大于0
			if (prevAddDays > 0) {
				// 从1开始添加
				for (let i = 0; i < prevAddDays; i++) {
					let date = new Date(year, month, -i);
					let item = {
						year: date.getFullYear(),
						month: date.getMonth(),
						day: date.getDate(),
						date: date
					};
					prevDays.unshift(item);
				}
			}

			// 这个月最后一天是周几
			const lastDay = new Date(year, month + 1, 0).getDay();

			// 月后面需要添加的天数
			const nextDays = [];
			const nextAddDays = (_props?.weekStart === 0 ? 6 - lastDay : 7 - lastDay) + 14;
			// 如果需要添加的天数大于0
			if (nextAddDays > 0) {
				// 从1开始添加
				for (let i = 1; i <= nextAddDays; i++) {
					let date = new Date(year, month + 1, i);
					let item = {
						year: date.getFullYear(),
						month: date.getMonth(),
						day: date.getDate(),
						date: date
					};
					nextDays.push(item);
				}
			}

			// 最多 7 * 6 行
			const maxDays = 7 * 6;
			const nextDaysCount = Math.abs(maxDays - days.length - prevDays.length);
			const maxNextDays = nextDays.slice(0, nextDaysCount);

			// 组织数据
			const item = {
				year,
				month,
				days,
				prevDays,
				nextDays: maxNextDays
			};
			// 加入列表
			months.push(item);

			// 月份加一
			startDate.setMonth(month + 1);
		}

		return months;
	});

	// 是否禁用上一年切换按钮
	const _disabledPrevYear = computed(() => {
		const years = _months.value.map((item) => item.year);
		const minYear = Math.min(...years);
		return _currentYear.value <= minYear;
	});

	// 是否禁用下一年切换按钮
	const _disabledNextYear = computed(() => {
		const years = _months.value.map((item) => item.year);
		const maxYear = Math.max(...years);
		return _currentYear.value >= maxYear;
	});

	// 是否禁用上一月切换按钮
	const _disabledPrevMonth = computed(() => {
		return _current.value === 0;
	});

	// 是否禁用下一月切换按钮
	const _disabledNextMonth = computed(() => {
		return _current.value === _months.value.length - 1;
	});

	// 禁用的日期
	const _disabledDates = computed(() => {
		return _props.disabledDates.map((item) => dateParse(item));
	});

	// 监听选中的日期，触发 onSelect 事件
	watch(
		() => _selectedDates.value,
		(newValue, oldValue) => {
			// 触发 onSelect 事件
			_emits("onSelect", {
				selectedDates: newValue.sort((a, b) => a.date - b.date)
			});
		},
		{
			deep: true
		}
	);

	// 设置默认选中的日期
	watch(
		() => _props.defaultDates,
		(newVal) => {
			if (newVal?.length) {
				const days = [];
				newVal.forEach((item) => {
					const dayDate = dateParse(item);
					days.push({
						year: dayDate.getFullYear(),
						month: dayDate.getMonth(),
						day: dayDate.getDate(),
						date: dayDate
					});
				});
				_selectedDates.value = days;
			}
		},
		{ immediate: true, deep: true }
	);

	// 设置默认展示的日期
	watch(
		_months,
		(newValue, oldValue) => {
			if (_props.currentDate && _current.value === -1) {
				const currentDate = dateParse(_props.currentDate);
				const index = newValue.findIndex((item) => {
					return item?.year === currentDate.getFullYear() && item?.month === currentDate.getMonth();
				});
				if (index !== -1) {
					_current.value = index;
				}
			}
		},
		{ immediate: true, deep: true }
	);

	// -------------------------------------------------------------------------------- Events
	// 切换事件
	function _onChange(e) {
		_current.value = e.detail.current;
	}

	// 上一年
	function _onPrevYear() {
		if (_current.value - 12 < 0) _current.value = 0;
		else _current.value -= 12;
	}

	// 下一年
	function _onNextYear() {
		if (_current.value + 12 >= _months.value.length) _current.value = _months.value.length - 1;
		else _current.value += 12;
	}

	// 上一月
	function _onPrevMonth() {
		_current.value--;
	}

	// 下一月
	function _onNextMonth() {
		_current.value++;
	}

	// 点击日期
	function _onClick(day) {
		// 选择单个日期
		if (_props.selectType === "single") {
			_selectedDates.value = [day];
		}

		// 选择多个日期
		else if (_props.selectType === "multiple") {
			const index = _selectedDates.value.findIndex((item) => {
				return _isSameDate(day.date, item?.date);
			});
			if (index === -1) {
				_selectedDates.value.push(day);
			} else {
				_selectedDates.value.splice(index, 1);
			}
		}

		// 选择日期区间
		else if (_props.selectType === "range") {
			if (_selectedDates.value.length === 1) {
				_selectedDates.value.push(day);
			} else {
				_selectedDates.value = [day];
			}
		}
	}

	// 是否选中
	function _isSelected(day) {
		// 选择单个日期
		if (_props.selectType === "single") {
			const selectedDate = _selectedDates.value[0]?.date;
			return _isSameDate(day.date, selectedDate);
		}

		// 选择多个日期
		else if (_props.selectType === "multiple") {
			return _selectedDates.value.some((item) => _isSameDate(day.date, item?.date));
		}

		// 选择日期区间
		else if (_props.selectType === "range") {
			if (_selectedDates.value.length === 0) return false;
			if (_selectedDates.value.length === 1) {
				const selectedDate = _selectedDates.value[0]?.date;
				return _isSameDate(day.date, selectedDate);
			}
			if (_selectedDates.value.length === 2) {
				const firstDate = _selectedDates.value[0].date;
				const lastDate = _selectedDates.value[1].date;
				if (firstDate <= lastDate) return day.date >= firstDate && day.date <= lastDate;
				else return day.date >= lastDate && day.date <= firstDate;
			}
		}
	}

	// 计算 day classes
	function _calcDayClasses(day) {
		const array = [];

		// 是否禁用
		if (_isDisabled(day)) array.push("pure-calendar__month__day--disabled");

		// 是否选中
		if (_isSelected(day)) array.push("pure-calendar__month__day--selected");

		// 选择多个日期
		if (_props.selectType === "multiple") {
			// 用于存储连续的日期数组
			const continuous = [];

			// 升序排序
			const selectedDates = _selectedDates.value.sort((a, b) => a.date - b.date);

			// 找到连续的日期并切分成二维数组
			let items = [];
			for (let i = 0; i < selectedDates.length; i++) {
				const item = selectedDates[i];
				if (i === 0) {
					items.push(item);
				} else {
					const lastItem = items[items.length - 1];
					const nextDate = new Date(lastItem.year, lastItem.month, lastItem.day + 1);
					const itemDate = new Date(item.year, item.month, item.day);
					if (itemDate.getTime() === nextDate.getTime()) {
						items.push(item);
					} else {
						continuous.push(items);
						items = [item];
					}
				}
			}
			continuous.push(items);

			// 循环处理连续的日期数组
			for (let i = 0; i < continuous.length; i++) {
				const items = continuous[i];
				const firstItem = items[0];
				const lastItem = items[items.length - 1];

				// 大于2个才需要处理
				if (items?.length >= 2) {
					// 第一个选中的加上左上、左下圆角
					if (_isSameDate(day.date, firstItem?.date)) array.push("pure-calendar__month__day--first");
					// 最后一个选中的加上右上、右下圆角
					else if (_isSameDate(day.date, lastItem?.date)) array.push("pure-calendar__month__day--last");
					// 中间的选中的去掉圆角
					else if (day.date > firstItem?.date && day.date < lastItem?.date) {
						array.push("pure-calendar__month__day--in");
					}
				}
			}
		}

		// 选择日期区间
		if (_props.selectType === "range") {
			// 第一个选中的
			let firstDate = _selectedDates.value[0]?.date;
			// 最后一个选中的
			let lastDate = _selectedDates.value[1]?.date;

			// 如果第一项的日期大于第二项的日期，交换
			if (firstDate > lastDate) {
				[firstDate, lastDate] = [lastDate, firstDate];
			}

			// 选中了一项
			if (_selectedDates.value.length === 1 && _isSameDate(day.date, firstDate))
				array.push("pure-calendar__month__day--first");
			// 选中了两项
			else if (_selectedDates.value.length === 2) {
				// 第一个选中的去掉右上、右下圆角
				if (_isSameDate(day.date, firstDate)) array.push("pure-calendar__month__day--first");
				// 最后一个选中的去掉左上、左下圆角
				else if (_isSameDate(day.date, lastDate)) array.push("pure-calendar__month__day--last");
				// 中间的选中的去掉圆角
				else if (firstDate <= lastDate) {
					if (day.date > firstDate && day.date < lastDate) {
						array.push("pure-calendar__month__day--middle");
					}
				} else if (firstDate >= lastDate) {
					if (day.date > lastDate && day.date < firstDate) {
						array.push("pure-calendar__month__day--middle");
					}
				}
			}
		}

		return array;
	}

	// 比较两个日期是否相等
	function _isSameDate(date1, date2) {
		if (!date1 || !date2) return false;
		date1 = dateParse(date1);
		date2 = dateParse(date2);
		return (
			date1?.getFullYear() === date2?.getFullYear() &&
			date1?.getMonth() === date2?.getMonth() &&
			date1?.getDate() === date2?.getDate()
		);
	}

	// 是否禁用
	function _isDisabled(day) {
		return _disabledDates.value.some((item) => _isSameDate(day.date, item));
	}

	// 显示的日期文本
	function _calcDayText(day) {
		return day.day;
	}

	// 显示的月份文本
	function _calcMonthText(month) {
		return month.month + 1;
	}
</script>

<style scoped lang="scss">
	@import "./style.scss";
</style>
